/***************************************************************************
 *   Copyright (C) 2004 by cyril dupuit                                    *
 *   cyrildupuit@hotmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//*****************************************************************************
// Nom du module : ThredInf.c
// Description :  Obtenir des infos sur les threads.
//*****************************************************************************
 
// Historique :
// 28/10/04 : Creation du module V1.0  

#include "Kernel/Core.h"
#include "Misc/Console.h"
#include "Lib/Queue.h"
#include "Misc/ThredInf.h"
#include "Kernel/Schedule.h"
#include "Arch/Pentium/Kernel/Cpu.h"
#include "Kernel/Parental.h"
#include "Arch/Pentium/Kernel/malloc.h"
#include "Lib/StdLib/stdio.h"
#include "Lib/StdLib/string.h"
#include "Kernel/Thread.h"
#include "Kernel/Errors.h"

//*****************************************************************************
// But de la fonction : Afficher une liste de tous les threads crees
// Entree : Aucune
// Parametre retourne : ERROR si memoire disponible insuffisante, TRUE sinon
//*****************************************************************************
Status_t ThreadListShow(void)
{
	QueueID_t QueueThreadList;
	ThreadID_t ThreadID;
	Ticks_t TaskTime, TotalTime;
	unsigned long TaskSwitchs, KernelSwitchs;
	char Tab[30];
	unsigned int Line = 0;	
	Coord_t X, Y;
	ThreadCount_t Count;

	Count = ThreadCount();
	QueueThreadList = QueueCreate(Count, QUEUE_FIFO);
	if(QueueThreadList == 0)
	{//Creation de la file impossible
		SetLastError(INSUFFICIENT_MEMORY_AVAILABLE);
		return ERROR;
	}
	
	if(printf("Liste des threads (%d) : \n", Count) == -1) return ERROR;
	if(ThreadGetList(QueueThreadList) == FALSE)
	{//Une tache a ete cree entre temps, la file d'attente est trop petite
		if(printf("La liste ci-dessous est incomplete, un thread vient d'etre cree !\n") == -1) return ERROR;
	}
	if(ConsoleGetCursorPosition(&X, &Y) == ERROR) return ERROR;
	if(printf("ID :") == -1) return ERROR;
	GotoXY(X + 10, Y);
	if(printf("Etat :") == -1) return ERROR;
	GotoXY(X + 30, Y);
	if(printf("Temps :") == -1) return ERROR;
	GotoXY(X + 50, Y);
	if(printf("Commutations :\n") == -1) return ERROR;
	//Affichage des parametres des taches
	ThreadID = (QueueID_t)QueueRead(QueueThreadList);
	while(ThreadID != 0)
	{//Afficher la liste des taches declarees
		if(ConsoleGetCursorPosition(&X, &Y) == ERROR) return ERROR;
		//Afficher le numero de la tache
		GotoXY(X, Y);
		if(printf("%ld", ThreadID) == -1) return ERROR;
		//Afficher l'etat de la tache
		if(ThreadStatusString(ThreadID, Tab, sizeof(Tab)) == ERROR) return ERROR;
		GotoXY(X + 10, Y);
		if(printf("%s", Tab) == -1) return ERROR;
		GotoXY(X + 30, Y);
		//Afficher l'utilisation
		if(ThreadTimeUsed(ThreadID, &TaskTime, &TotalTime) == ERROR) return ERROR;
		if(printf("%ld/%ld", TaskTime, TotalTime) == -1) return ERROR;
		//Afficher les commutations
		GotoXY(X + 50, Y);
		if(ThreadSwitchCount(ThreadID, &TaskSwitchs, &KernelSwitchs) == ERROR) return ERROR;
		if(printf("%ld/%ld\n", TaskSwitchs, KernelSwitchs) == -1) return ERROR;
		
		//Recuperer le prochain numero de tache
		ThreadID = (QueueID_t)QueueRead(QueueThreadList);
		Line = (Line + 1) % 20;//20 equivaut au nombre de ligne sur la console
		if((Line == 0)&&(ThreadID != 0))
		{//Demander a l'utilisateur de presser une touche pour voir la suite de l'ecran
			if(Pause() != TRUE)
			{//L'utilisateur stoppe la visualisation
				QueueDelete(&QueueThreadList);
				
				return TRUE;
			}
		}
	}
	
	QueueDelete(&QueueThreadList);

	return TRUE;
}

//*****************************************************************************
//But de la fonction : Afficher des informations detaillees sur un thread
// Entree :
//	ThreadID : Numero d'identification de la tache
// Parametre retourne : ERROR si le numero d'identification est invalide, TRUE
// sinon
//*****************************************************************************
Status_t ThreadShow(ThreadID_t ThreadID)
{
	char Tab[20];
	Stack_t StackUsed, StackSize;
	pFunction_t Entry;
	Priority_t Priority;
	Ticks_t TaskTime, TotalTime;
	unsigned long TaskSwitchs, KernelSwitchs;
	Status_t Status;
	
	if(ThreadIDVerify(ThreadID) == FALSE)
	{//Le numero d'identification n'est pas le bon
		SetLastError(INCORRECT_THREAD_ID);
		return ERROR;
	}
	if(printf("Informations specifiques a un thread : \n\n") == ERROR) return ERROR;
	//Afficher le numero d'identification du thread
	if(printf("ID : %ld \n", ThreadID) == -1) return ERROR;
	//Afficher le point d'entree du thread
	if(ThreadEntryGet(ThreadID, &Entry) == ERROR) return ERROR;
	if(printf("Point d'entree : %ld \n", (unsigned long)Entry) == -1) return ERROR;
	//Afficher la priorite de cette tache
	if(ThreadPriorityGet(ThreadID, &Priority) == ERROR) return ERROR;
	if(printf("Priorite : %ld \n", (unsigned long)Priority) == -1) return ERROR;
	//Afficher l'etat du thread
	if(ThreadStatusString(ThreadID, Tab, sizeof(Tab)) == ERROR) return ERROR;
	if(ThreadStatus(ThreadID, &Status) == ERROR) return ERROR;
	if(printf("Etat : %s ou 0x%x\n", Tab, Status) == -1) return ERROR;
	//Afficher l'utilisation de la pile
	if(ThreadStackUsed(ThreadID, &StackUsed, &StackSize) == ERROR) return ERROR;
	if(printf("Pile utilisee/totale : %ld/%ld\n", (unsigned long)StackUsed, (unsigned long)StackSize) == -1) return ERROR;
	//Afficher l'utilisation de la tache
	if(ThreadTimeUsed(ThreadID, &TaskTime, &TotalTime) == ERROR) return ERROR;
	if(printf("Temps utilise/total : %ld/%ld\n", TaskTime, TotalTime) == -1) return ERROR;
	//Affichage du taux de commutation
	if(ThreadSwitchCount(ThreadID, &TaskSwitchs, &KernelSwitchs) == ERROR) return ERROR;
	if(printf("Commutations tache/totale : %ld/%ld\n", TaskSwitchs, KernelSwitchs) == -1) return ERROR;
	
	return TRUE;
}

//*****************************************************************************
